home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / dev / src / adoc_src.lha / adoc-0.17 / adoc.yy < prev    next >
Encoding:
Text File  |  1995-03-20  |  13.1 KB  |  470 lines

  1. /*
  2.  *  ADOC.YY  -- Specification of the AUTODOC scanner
  3.  *
  4.  *  (c)Copyright 1995 by Tobias Ferber,  All Rights Reserved
  5.  *
  6.  *  This file is part of ADOC.
  7.  *
  8.  *  ADOC is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published
  10.  *  by the Free Software Foundation; either version 1 of the License,
  11.  *  or (at your option) any later version.
  12.  *
  13.  *  ADOC is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; see the file COPYING.  If not, write to
  20.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23. /* $VER: $Id: adoc.yy,v 1.13 1995/03/20 18:44:10 tf Exp $ */
  24.  
  25. %{
  26. #include <ctype.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <stdarg.h>
  30.  
  31. #include "adoc.h"
  32. #include "libfun.h"
  33. #include "flist.h"
  34. #include "debug.h"
  35.  
  36. /* In former versions of flex, yywrap had been defined as a macro */
  37.  
  38. #ifdef yywrap
  39. #undef yywrap
  40. #endif
  41.  
  42. /*
  43. ** local variables
  44. */
  45.  
  46. /* scanner's error stream */
  47. static FILE *ferr;
  48.  
  49. /* current input line (used for warnings and error messages) */
  50. static int scanner_line= 1;
  51.  
  52. /* set to the line in this file if an error occurs */
  53. static int scanner_error= 0;
  54.  
  55. /* name of the current input file */
  56. static char *scanner_infile= (char *)0;
  57.  
  58. /* pedanticness of warning method */
  59. static int warn_mask;
  60.  
  61. /* the last function which has been reported by funreport() */
  62. static char *report_fun= (char *)0;
  63.  
  64. /* string containing allowed characters for the comment type */
  65. static char *fun_type;
  66.  
  67. /*
  68. **  local functions
  69. */
  70.  
  71. static void funreport(const char *fmt, ...)
  72. {
  73.   va_list argp;
  74.   va_start(argp,fmt);
  75.   {
  76.     char *fun= getfun( (char *)0 );
  77.  
  78.     if(fun) {
  79.       if( !report_fun || strcmp(report_fun,fun) )
  80.         fprintf(ferr,"%s: In function `%s':\n",scanner_infile,fun);
  81.     }
  82.     else { /* !fun */
  83.       if(report_fun)
  84.         fprintf(ferr,"%s: At top level:\n",scanner_infile);
  85.     }
  86.     report_fun= fun;
  87.   }
  88.   fprintf(ferr,"%s: %d: ",scanner_infile,scanner_line);
  89.   vfprintf(ferr,(char *)fmt,argp);
  90.   fprintf(ferr,"\n");
  91.   fflush(ferr);
  92.  
  93.   va_end(argp);
  94. }
  95.  
  96.  
  97. /* Check the availability of section keywords in a function description.
  98.    This procedure is called from the scanner at the end of a function */
  99.  
  100. static void funcheck(int line, ...)
  101. {
  102.   char *fun, *arg;
  103.  
  104.   va_list argp;
  105.   va_start(argp,line);
  106.  
  107.   if( (fun= getfun((char *)0)) )
  108.   {
  109.     int missing= 0;
  110.  
  111.     for(arg= va_arg(argp, char *); arg && *arg; arg= va_arg(argp, char *))
  112.     {
  113.       if( !getsec(arg) )
  114.       {
  115.         if(missing)
  116.           fprintf(ferr," `%s'",arg);
  117.  
  118.         else /* first missing keyword */
  119.         {
  120.           if( !report_fun || strcmp(report_fun,fun) )
  121.           {
  122.             fprintf(ferr,"%s: In function `%s':\n",scanner_infile,fun);
  123.             report_fun= fun;
  124.           }
  125.           fprintf(ferr,"%s: %d: warning: missing keyword `%s'",scanner_infile,line,arg);
  126.         }
  127.  
  128.         ++missing;
  129.       }
  130.     }
  131.  
  132.     if(missing)
  133.       fprintf(ferr,"\n");
  134.   }
  135.   va_end(argp);
  136. }
  137.  
  138. /* remove white spaces from the left and/or right end of a string `s' */
  139.  
  140. static char *strip(char *s, char *lr)
  141. {
  142.   char *l, *r, *t;
  143.  
  144.   if( strchr(lr,'l') )
  145.   {
  146.     /* find the first non-white char `l' in `s' */
  147.     for(l=s; *l==' ' || *l=='\t'; l++) ;
  148.   }
  149.   else l=s;
  150.  
  151.   if( strchr(lr,'r') )
  152.   {
  153.     /* find the last non-white char `r' in `s' */
  154.     for(t= r= l; *t; t++)
  155.     {
  156.       if(*t!=' ' && *t!='\t' && *t!='\r' && *t!='\n')
  157.         r= t;
  158.     }
  159.  
  160.     if(r[0])
  161.       r[1]= '\0';
  162.   }
  163.  
  164.   return l;
  165. }
  166.  
  167. %}
  168.  
  169. BLACK        [^\n\r\f\t ]
  170. IDENT        [a-zA-Z0-9\-_]+
  171. AST          "*"
  172. NL           (\r)|(\n)|(\r\n)|(\n\r)
  173.  
  174. /* the context has been moved to the rule section
  175.    because of problems with former versions of lex */
  176.  
  177. FUN_BEGIN    {BLACK}{AST}{3}.{2}{AST}{1}" "
  178. FUN_IDENT    {IDENT}"/"{IDENT}
  179. FUN_SECTION  {BLACK}[ \t]+[A-Z]{2}[A-Z ]*
  180. FUN_TEXT     {BLACK}(([ \t].*)?)
  181. FUN_END      {BLACK}{AST}{2}
  182.  
  183. /*
  184.  *  eXclusive scanner modes:
  185.  *
  186.  *  INITIAL   skip source-code
  187.  *  EXPECT    we just read a {FUN_BEGIN} and expect a {FUN_IDENT} now to enter <SKIP> mode
  188.  *  SKIP      skip the rest of the line, then enter <FUN> mode
  189.  *  FUN       collecting data in a comment section.  {FUN_END} switches back to <INITIAL> mode again
  190.  */
  191.  
  192. %x EXPECT SKIP FUN
  193.  
  194. %%
  195.  
  196. <INITIAL>^{FUN_BEGIN}           { if( strchr(fun_type,yytext[4]) || strchr(fun_type,yytext[5]) )
  197.                                   {
  198.                                     D(bug("line %ld: <%c%c>",scanner_line,yytext[4],yytext[5]));
  199.                                     BEGIN(EXPECT);
  200.                                   }
  201.                                 }
  202.  
  203. <EXPECT>{FUN_IDENT}             { D(bug("BEGIN function `%s'",yytext));
  204.  
  205.                                   if( newfun(yytext) )
  206.                                   {
  207.                                     funreport("error adding function `%s' -- not enough memory?",yytext);
  208.                                     return scanner_error= __LINE__;
  209.                                   }
  210.                                   BEGIN(SKIP);
  211.                                 }
  212.  
  213. <EXPECT>.                       {                  BEGIN(INITIAL); }
  214. <EXPECT>{NL}                    { ++scanner_line;  BEGIN(INITIAL); }
  215.  
  216. <SKIP>.*{NL}                    { yyless(yyleng-1); BEGIN(FUN); }
  217.  
  218.  
  219.  /* There had been warnings because of a "dangerous trailing context"
  220.     when using <FUN>^{FUN_SECTION}/{NL} and <FUN>^{FUN_TEXT}/{NL}.
  221.  
  222.     Note: we currently need the yyless() calls and put back the '\n' into
  223.     the input to make sure the `^' in is recognized afterwards */
  224.  
  225.  
  226. <FUN>^{FUN_SECTION}{NL}         { yyless(yyleng-1);
  227.                                   { /* make a temporary copy of yytext */
  228.                                     register char *t= strdup(&yytext[1]);
  229.  
  230.                                     if(t)
  231.                                     {
  232.                                       /* strip white chars on both sides of yytext */
  233.                                       register char *s= strip(t,"lr");
  234.                                       D(bug("... section `%s'",s));
  235.  
  236.                                       if( warn_mask & WARN_UNKNOWN_KEYWORDS )
  237.                                       {
  238.                                         if( !strarg(s,"NAME",
  239.                                                       "SYNOPSIS",
  240.                                                       "FUNCTION",
  241.                                                       "INPUTS",
  242.                                                       "RESULT",
  243.                                                       "EXAMPLE",
  244.                                                       "NOTES",
  245.                                                       "BUGS",
  246.                                                       "SEE ALSO", "") )
  247.  
  248.                                           funreport("warning: unknown section keyword `%s'",s);
  249.                                       }
  250.  
  251.                                       if( newsec(s) )
  252.                                       {
  253.                                         funreport("error adding section keyword `%s' -- not enough memory?",s);
  254.                                         return scanner_error= __LINE__;
  255.                                       }
  256.                                       free(t);
  257.                                     }
  258.                                     else /* !t */
  259.                                     {
  260.                                       funreport("ran out of memory");
  261.                                       return scanner_error= __LINE__;
  262.                                     }
  263.                                   }
  264.                                 }
  265.  
  266. <FUN>^{FUN_TEXT}{NL}            { yyless(yyleng-1);
  267.                                   { /* make a temporary copy of yytext */
  268.                                     register char *t= strdup(&yytext[1]);
  269.  
  270.                                     if(t)
  271.                                     {
  272.                                       /* remove trailing white spaces - especially the {NL} */
  273.                                       register char *s= strip(t,"r");
  274.  
  275.                                       if( addtext(s) > 0 )
  276.                                       {
  277.                                         funreport("error adding text line -- not enough memory?");
  278.                                         return scanner_error= __LINE__;
  279.                                       }
  280.  
  281.                                       free(t);
  282.                                     }
  283.                                     else /* !t */
  284.                                     {
  285.                                       funreport("ran out of memory");
  286.                                       return scanner_error= __LINE__;
  287.                                     }
  288.                                   }
  289.                                 }
  290.  
  291. <FUN>^{FUN_END}.*{NL}           { D(bug("END function"));
  292.  
  293.                                   if( warn_mask & WARN_MISSING_KEYWORDS )
  294.                                   {
  295.                                     funcheck( scanner_line, "NAME",
  296.                                                             "SYNOPSIS",
  297.                                                             "FUNCTION",
  298.                                                             "INPUTS",
  299.                                                             "RESULT",
  300.                                                             "EXAMPLE",
  301.                                                             "NOTES",
  302.                                                             "BUGS",
  303.                                                             "SEE ALSO", "");
  304.                                   }
  305.                                   yyless(yyleng-1);
  306.                                   BEGIN(INITIAL);
  307.                                 }
  308.  
  309. <FUN>^[ \t]*{NL}                { if( warn_mask & WARN_BROKEN_COMMENTS )
  310.                                     funreport("warning: broken autodoc comment");
  311.                                   ++scanner_line;
  312.                                 }
  313.  
  314. <FUN>.                          { if( warn_mask & WARN_STRANGE_TEXT )
  315.                                     funreport("warning: line does not match {FUN_TEXT}");
  316.                                 }
  317.  
  318. <INITIAL,EXPECT,SKIP,FUN>{NL}   { scanner_line++; }
  319. <INITIAL,EXPECT,SKIP,FUN>.      /* eat up anything else in <*> mode */
  320.  
  321. <EXPECT,SKIP,FUN><<EOF>>        { funreport("unexpected end of file");
  322.                                   return scanner_error= __LINE__;
  323.                                 }
  324.  
  325. <INITIAL><<EOF>>                { D(bug("%d lines at <<EOF>>",scanner_line));
  326.                                   yyterminate();
  327.                                 }
  328.  
  329. %%
  330.  
  331. /* This function opens the scanner stream for the file `fname' and
  332.    initializes `scanner_infile' and `scanner_line' */
  333.  
  334. static int init_scanner(char *fname)
  335. {
  336.  
  337. #if !defined(USE_YYRESTART)
  338.   static int num_calls= 0;
  339. #endif
  340.  
  341.   int result= 0;
  342.  
  343.   if(fname)
  344.   {
  345.     if(*fname)
  346.     {
  347.       FILE *fp= fopen(fname,"r");
  348.  
  349.       if(fp)
  350.       {
  351.         scanner_infile= fname;
  352.  
  353.         if(yyin && (yyin !=stdin))
  354.           fclose(yyin);
  355.  
  356. #if defined(USE_YYRESTART)
  357.         yyrestart(fp);
  358. #else
  359.         yyin= fp;
  360.         if(++num_calls > 1) YY_NEW_FILE;
  361. #endif
  362.       }
  363.       else /* !fp */
  364.       {
  365.         fprintf(ferr,"scanner error: cannot read from `%s'\n",fname);
  366.         scanner_error= __LINE__;
  367.         result= 1;
  368.       }
  369.     }
  370.     else /* !*fname */
  371.     {
  372.       scanner_infile= "stdin";
  373.  
  374.       if(yyin && (yyin !=stdin))
  375.         fclose(yyin);
  376.  
  377. #if defined(USE_YYRESTART)
  378.       yyrestart(stdin);
  379. #else
  380.       yyin= stdin;
  381.       if(++num_calls > 1) YY_NEW_FILE;
  382. #endif
  383.     }
  384.   }
  385.   else /* !fname */
  386.   {
  387.     scanner_infile= (char *)0;
  388.     result= 1;
  389.   }
  390.  
  391.   /* reset the line counter */
  392.   scanner_line= 1;
  393.  
  394. #ifdef DEBUG
  395.   if(scanner_infile) 
  396.     D(bug("--> `%s'", scanner_infile));
  397.   else
  398.     D(bug("--> end of scanner input queue"));
  399. #endif DEBUG
  400.  
  401.   return result;
  402. }
  403.  
  404. /* In former versions of flex, yywrap had been defined as a macro */
  405.  
  406. #ifdef yywrap
  407. #undef yywrap
  408. #endif
  409.  
  410. /*
  411.  *  yywrap() is called by yylex() each time the EOF is reached.
  412.  *  It returns 0 if there is another file to be scanned or
  413.  *             1 if all scanning is done.
  414.  *  Our yywrap() will take the next file from the flist queue.
  415.  */
  416.  
  417. int yywrap()
  418. {
  419.   int result= 1;
  420.  
  421.   if( !scanner_error )
  422.   {
  423.     flist_nextfile();
  424.     result= init_scanner( flist_getname() );
  425.   }
  426.  
  427.   return result;
  428. }
  429.  
  430.  
  431. int read_source(char *_fun_type, int _warn_mask)
  432. {
  433.   int err= 0;
  434.  
  435.   D(bug_enter("read_source"));
  436.  
  437.   /* copy parameters to the local variables */
  438.  
  439.   fun_type  = _fun_type;
  440.   warn_mask = _warn_mask;
  441.  
  442.   /* initialize the error stream */
  443.  
  444.   ferr= get_ferr();
  445.  
  446.   /* initialize the scanner */
  447.  
  448.   if( init_scanner( flist_getname() ) == 0 )
  449.   {
  450.     if(scanner_error == 0)
  451.     {
  452.       /* yylex() returns an integer != 0 if an error occured. */
  453.       err= yylex();
  454.     }
  455.   }
  456.   else
  457.   {
  458.     D(bug("ooops!?  filename queue is empty?"));
  459.   }
  460.  
  461.   /* errors from yywrap() are returned as negative values */
  462.  
  463.   if(!err && scanner_error)
  464.     err= -scanner_error;
  465.  
  466.   D(bug_leave("read_source (%s)",err ? "failed":"successful"));
  467.  
  468.   return err;
  469. }
  470.